#include <IRQDispatcher.h>
#include <DescriptorTables.h>

IRQDispatcher::IRQDispatcher()
{
  // Initialise the resource and functions.
  resource = new Resource((Callable*)this, "IRQDispatcher");
  resource->add((Resource::Call3)&IRQDispatcher::registerHandler, IRQDispatcher_IF::registerHandler);
  resource->add((Resource::Call2)&IRQDispatcher::unregisterHandler, IRQDispatcher_IF::unregisterHandler);

//   for(int i = 0; i < 16; i++)
//   {
//     maps[i] = NULL;
//   }
}


IRQDispatcher::~IRQDispatcher()
{
}

void IRQDispatcher::registerHandler(int irq, u32int pid, int handlerIdx)
{
  DEBUG_VERBOSE("IRQ::registerHandler(" << hex << irq << ", " << pid << ", " << handlerIdx << ").");
  // irq>0 because we cannot remap the handler for the timer!
  ASSERT(irq > 0 && irq < 16);
  // Has this irq been registered already?
  HandlerMap *map;
  if (maps[irq])
  {
    map = maps[irq];
  }
  else
  {
    map = new HandlerMap();
    maps[irq] = map;
    // Register the IRQ!
    descriptorTables.registerIrq(irq, this);
  }
  
  Process *process = processManager->getProcess(pid);
  
  // Add this process to the map.
  map->add(process, handlerIdx);
}

void IRQDispatcher::unregisterHandler(int irq, u32int pid)
{
  DEBUG_VERBOSE("IRQ::unregisterHandler(" << hex << irq << ", " << pid << ").");
  // irq>0 because we cannot remap the handler for the timer!
  ASSERT(irq > 0 && irq < 16);
  
  HandlerMap *map = maps[irq];
  ASSERT(map);
  
  Process *process = processManager->getProcess(pid);
  
  map->remove(process);
  if (map->length() == 0)
  {
    // If this map is now empty, delete it and unregister the irq.
    delete map;
    maps[irq] = NULL;
    descriptorTables.unregisterIrq(irq);
  }
}

void IRQDispatcher::run(Registers *r)
{
  u32int irq = r->int_no-32;
  HandlerMap *map = maps[irq];
  DEBUG_VERBOSE("Recieved IRQ " << dec << irq << ".");
  for (int i = 0; i < map->length(); i++)
  {
    Process *process = map->getKeyByIndex(i);
    int handlerIdx = map->getByIndex(i);
    process->sendSignal(handlerIdx);
  }
}
